﻿@page "/tasks"
@using Gurux.DLMS.AMI.Components.Enums
@using Gurux.DLMS.AMI.Shared.DIs
@using Gurux.DLMS.AMI.Shared.DTOs.Authentication
@using Gurux.DLMS.AMI.Shared.Enums
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.Rest
@using Microsoft.AspNetCore.SignalR.Client
@using Gurux.DLMS.AMI.Shared
@using Gurux.DLMS.AMI.Client.Helpers
@using Gurux.DLMS.AMI.Module

@attribute [Authorize(Roles = "Admin, TaskManager")]
@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject ConfirmBase Confirm
@inject IGXNotifier2 Notifier
@implements IDisposable
@implements IAmiComponent

@if (Title)
{
    <PageTitle>@Properties.Resources.Tasks (@Properties.Resources.Total: @Total)</PageTitle>
}

<MenuControl RightCorner="true">
    <ChildContent>
        <MenuItem Text="@Properties.Resources.Remove" Icon="oi oi-trash" OnClick="@OnRemove" />
        <MenuItem Text="@Properties.Resources.Clear" Icon="oi oi-trash" OnClick="@OnClear" />
    </ChildContent>
</MenuControl>

<GXTable @ref="table"
         Context="task"
         ItemsProvider="@GetItems"
         SelectionMode="SelectionMode.Multiple"
         ShowRemoved="false"
         ShowAllUsers="@Header"
         Columns="@Columns"
         Filter="@Filter"
         OnSearch="@Updated">
    <FilterContent>
        <th>
            <!--Target-->
        </th>
        <Fh>
            <input class="form-control" placeholder="按创建时间..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.CreationTime = @StatusTile.ToDateTime(__e.Value))" />
        </Fh>
        <Fh Visibility="Visibility.ExtraSmall">
            <!--Task type-->
        </Fh>
        <Fh Visibility="Visibility.Small">
            <input class="form-control" placeholder="Filter by start time..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.Start = @StatusTile.ToDateTime(__e.Value))" />
        </Fh>
        <Fh Visibility="Visibility.Medium">
            <input class="form-control" placeholder="Filter by end time..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.Ready = @StatusTile.ToDateTime(__e.Value))" />
        </Fh>
        <Fh Visibility="Visibility.Large">
            <!--Result.-->
        </Fh>
    </FilterContent>
    <HeaderContent>
        <Th Id="Target">@Properties.Resources.Target</Th>
            <Th Id="CreationTime" SortMode="SortMode.Descending">@Properties.Resources.CreationTime</Th>
            <Th Id="TaskType" Visibility="Visibility.ExtraSmall">@Properties.Resources.TaskType</Th>
            <Th Id="Start" Visibility="Visibility.Small">@Properties.Resources.StartTime</Th>
            <Th Id="Ready" Visibility="Visibility.Medium">@Properties.Resources.CompletedTime</Th>
            <Th Id="Result" Visibility="Visibility.Large">@Properties.Resources.Result</Th>
        </HeaderContent>
        <ItemContent>
            <Td>@task.Target</Td>
            <Td>@task.CreationTime</Td>
            <Td Visibility="Visibility.ExtraSmall">@TaskTypeToString(task.TaskType)</Td>
            <Td Visibility="Visibility.Small">@task.Start</Td>
            <Td Visibility="Visibility.Medium">@task.Ready</Td>
            <Td Visibility="Visibility.Large">@task.Result</Td>
        </ItemContent>
    </GXTable>
    <br />
    <Confirm @ref="RemoveConfirmation"
             ConfirmationChanged="OnDeleteConfirmation"
             AllowDelete="false"
             OkTitle="@Properties.Resources.Remove"
             ConfirmationMessage=""
             ConfirmationTitle="@Properties.Resources.AreYouSureYouWantToDeleteSelectedItems">
    </Confirm>

    <Confirm @ref="ClearConfirmation"
             ConfirmationChanged="OnClearConfirmation"
             ConfirmationTitle=@Properties.Resources.ConfirmDataClear
             AllowDelete="false"
             OkTitle="@Properties.Resources.Clear"
             ConfirmationMessage="@Properties.Resources.AreYouSureYouWantToClearTasks">
    </Confirm>

    @code {
    /// <summary>
    /// Action.
    /// </summary>
    [Parameter]
    public string? Action { get; set; }

    /// <summary>
    /// Selected schedule ID.
    /// </summary>
    [Parameter]
    public Guid? Id { get; set; }

    /// <inheritdoc />
    public string Name
    {
        get
        {
            return Gurux.DLMS.AMI.Client.Properties.Resources.Tasks;
        }
    }

    /// <inheritdoc />
    public Type? ConfigurationUI
    {
        get
        {
            return null;
        }
    }

    /// <inheritdoc />
    public string? Icon
    {
        get
        {
            return "oi oi-pulse";
        }
    }

    /// <summary>
    /// Amount of the tasks shown on the view.
    /// </summary>
    [Parameter]
    public int Count { get; set; } = 0;

    /// <summary>
    /// Is filter shown.
    /// </summary>
    [Parameter]
    public bool Filter { get; set; } = true;

    /// <summary>
    /// Is header shown.
    /// </summary>
    [Parameter]
    public bool Header { get; set; } = true;

    /// <summary>
    /// Is edit allowed.
    /// </summary>
    [Parameter]
    public bool CanEdit { get; set; } = true;

    /// <summary>
    /// Available columns.
    /// </summary>
    [Parameter]
    public string[]? Columns { get; set; }

    /// <summary>
    /// Is title shown.
    /// </summary>
    [Parameter]
    public bool Title { get; set; } = true;

    /// <summary>
    /// Total numbers of rows in the database.
    /// </summary>
    internal int Total
    {
        get
        {
            if (table == null)
            {
                return 0;
            }
            return table.TotalCount;
        }
    }


    private static string TaskTypeToString(TaskType? type)
    {
        string str;
        switch (type)
        {
            case TaskType.Read:
                str = Properties.Resources.Read;
                break;
            case TaskType.Write:
                str = Properties.Resources.Write;
                break;
            case TaskType.Action:
                str = Properties.Resources.Action;
                break;
            case TaskType.Refresh:
                str = Properties.Resources.Refresh;
                break;
            default:
                str = type.ToString();
                break;
        }
        return str;
    }

    /// <summary>
    /// Task filter.
    ///</summary>
    private GXTask filter = new GXTask();

    /// <summary>
    /// User is verified before tasks are removed.
    ///</summary>
    protected ConfirmBase? RemoveConfirmation;

    /// <summary>
    /// User is verified before tasks are cleared.
    ///</summary>
    protected ConfirmBase? ClearConfirmation;
    /// <summary>
    /// Table reference.
    /// </summary>
    protected GXTable<GXTask>? table;

    /// <summary>
    /// Update table.
    /// </summary>
    protected async Task Updated()
    {
        try
        {
            if (table != null)
            {
                Notifier.ClearStatus();
                await table.RefreshDataAsync(true);
            }
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
    }

    /// <summary>
    /// Task status has changed.
    /// </summary>
    /// <param name="tasks">Changed tasks.</param>
    protected bool StateChanged(IEnumerable<GXTask> tasks)
    {
        try
        {
            bool updated = false;
            if (table?.Items != null)
            {
                foreach (var it in tasks)
                {
                    GXTask? task = table.Items.Where(w => w.Id == it.Id).SingleOrDefault();
                    if (task != null)
                    {
                        updated = true;
                        if (it.Start != null)
                        {
                            task.Start = it.Start;
                        }
                        if (it.Ready != null)
                        {
                            task.Ready = it.Ready;
                            task.Result = it.Result;
                        }
                    }
                    else
                    {
                        //Unknown task executed.
                        //This might happen with pagination if task is not in the visible items.
                        return true;
                    }
                }
            }
            if (updated)
            {
                StateHasChanged();
            }
        }
        catch (Exception)
        {
        }
        return false;
    }

    protected override async Task OnInitializedAsync()
    {
        //Wait until table is loaded. Don't remove this or table is null and last settings are not available.
        await Task.Delay(1);
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            Notifier.On<IEnumerable<GXTask>>(this, nameof(IGXHubEvents.TaskAdd), async (tasks) =>
            {
                await Updated();
            });
            Notifier.On<IEnumerable<GXTask>>(this, nameof(IGXHubEvents.TaskDelete), async (tasks) =>
            {
                await Updated();
            });
            Notifier.On<IEnumerable<GXTask>>(this, nameof(IGXHubEvents.TaskUpdate), async (tasks) =>
            {
                if (StateChanged(tasks))
                {
                    await Updated();
                }
            });
            Notifier.On<IEnumerable<GXUser>>(this, nameof(IGXHubEvents.TaskClear), async (tasks) =>
            {
                await Updated();
            });
            Notifier.Clear();
            Notifier.UpdateButtons();
            if (table != null && Id != null)
            {
                //Get last selected item.
                table.Active = new GXTask() { Id = Id.Value };
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
        finally
        {
            Notifier.ProgressEnd();
        }
    }

    private async ValueTask<ItemsProviderResult<GXTask>> GetItems(GXItemsProviderRequest request)
    {
        //Don't clear status or error is lost.
        Notifier.ProgressStart();
        try
        {
            ListTasks req = new ListTasks()
                {
                    Index = request.StartIndex,
                    Count = request.Count,
                    Filter = filter,
                    OrderBy = request.OrderBy,
                    Descending = request.Descending,
                    AllUsers = request.ShowAllUserData
                };
            if (Count != 0)
            {
                req.Count = Count;
            }
            var ret = await Http.PostAsJson<ListTasksResponse>("api/Task/List", req, request.CancellationToken);
            if (ret.Tasks != null)
            {
                //Mark tasks as seen.
                await Notifier.Mark(Http, TargetType.Task, ret.Tasks.Max(s => s.CreationTime));
                return new ItemsProviderResult<GXTask>(ret.Tasks, ret.Count);
            }
        }
        catch (TaskCanceledException)
        {
            //Let the table component handle this.
            throw;
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
        finally
        {
            Notifier.ProgressEnd();
        }
        return default;
    }

    /// <summary>
    /// Remove selected tasks.
    /// </summary>
    public void OnRemove()
    {
        try
        {
            if (table == null || !table.SelectedItems.Any())
            {
                throw new Exception(Gurux.DLMS.AMI.Client.Properties.Resources.NoItemIsSelected);
            }
            RemoveConfirmation?.Show();
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
    }

    /// <summary>
    /// Clear the all tasks.
    /// </summary>
    public void OnClear()
    {
        ClearConfirmation?.Show();
    }

    /// <summary>
    /// Delete the selected task list.
    /// </summary>
    public async Task OnDeleteConfirmation(ConfirmArgs args)
    {
        try
        {
            if (table != null && args.Confirm)
            {
                DeleteTask req = new DeleteTask();
                req.Ids = table.SelectedItems.Select(w => w.Id).ToArray();
                await Http.PostAsJson<DeleteTaskResponse>("api/Task/Delete", req);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
    }

    /// <summary>
    /// Clear user tasks.
    /// </summary>
    public async Task OnClearConfirmation(ConfirmArgs args)
    {
        try
        {
            if (args.Confirm)
            {
                ClearTask req = new ClearTask();
                await Http.PostAsJson<ClearTaskResponse>("api/Task/Clear", req);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier.ProcessError(ex);
        }
    }

    public void Dispose()
    {
        Notifier.RemoveListener(this);
    }
}
